import java.util.Enumeration;

import javax.media.j3d.Appearance;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.Node;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnCollisionEntry;
import javax.media.j3d.WakeupOnCollisionExit;
import javax.media.j3d.WakeupOnCollisionMovement;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import org.haptiklibrary.HaptikData;
import org.haptiklibrary.HaptikDevice;

import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.picking.PickResult;

/**
 * A simple collision detector class. This responds to a collision event by
 * printing a message with information about the type of collision event and the
 * object involved. This is a variation of the CollisionDetector class that
 * prints information about the object that is associated with this behaviour
 * rather than the object that has been collided with. An example of its use is
 * given in the SimpleCollision2 class.
 * 
 * @author Yi Wu
 * @version 1.0
 * @see CollisionDetector
 * @see SceneNCollision
 */class PuckCollisionDetector extends Behavior {
  /** The shape that is being watched for collisions. */
  protected TransformGroup puckGrp;
  protected Vector3f puckPosition;
  protected Transform3D puckTrans;
  public Vector3f V;
  
  protected TransformGroup handleGrp;
  protected Vector3f handlePosition;
  protected Transform3D handleTrans;
  
  protected int id;
/*	for the falcon connection
 * private float[] position = new float[3];
	private float[] velocity = new float[3];
	private float[] acceleration = new float[3];
	private float[] force = new float[3];
	private float[] damper = new float[3];
	private Vector3f tmpv;
	private long t = 0L;
	private float dt = 0f;
	private long t_now = 0L;
	
	private float mass = 0.5f;//0.125f;	
	private float damper_coeff = 0.8f;
	
	private float[] scale = new float[3];
	private float[] cali = new float[3];
 */
  protected WakeupCondition m_WakeupCondition = null;

  /**
   * @param theShape
   *            Shape3D that is to be watched for collisions.
   * @param theBounds
   *            Bounds that define the active region for this behaviour
   */
  public PuckCollisionDetector(TransformGroup theShape,TransformGroup handle,Vector3f Velocity, int player) {
    puckGrp = theShape;
    puckTrans= new Transform3D();
    puckPosition= new Vector3f();
    handleGrp = handle;
    handleTrans= new Transform3D();
    handlePosition= new Vector3f();
    id=player;

    V=Velocity;
  //  this.secondShape= sndShape;

  }

  /**
   * This sets up the criteria for triggering the behaviour. It creates an
   * entry, exit and movement trigger, OR's these together and then sets the
   * OR'ed criterion as the wake up condition.
   */
  public void initialize() {	   
	  this.wakeupOn(new WakeupOnElapsedFrames(0));
	  System.out.println( "wake up 0!" );
	  
	  //save the WakeupCriterion for the behavior
	  setSchedulingBounds(new BoundingSphere(new Point3d(0.0d,0.0d,0.0d), 3000.0d));
	 
  }

  /**
   * This is where the work is done. This identifies the type of collision
   * (entry, exit or movement) and prints a message stating that an object has
   * collided with this object. The userData field of the shape associated
   * with this collision detector # is used to identify the object. Finally,
   * the wake up condition is set to be the OR'ed criterion again.
   */
  public void processStimulus( Enumeration criteria )
  {
  	
  	//System.out.println("start:"+V);
  		puckGrp.getTransform(puckTrans);
	    puckTrans.get(puckPosition);
	    
	    handleGrp.getTransform(handleTrans);
	    handleTrans.get(handlePosition);
  	
  	if((id==2&&puckPosition.z>0)||id==1&&puckPosition.z<0)
  {  	    
  	    if(puckPosition.z>14.1)  //if the handle hit the up wall
  	    {
  	  	  if(Math.abs(puckPosition.x)<0.6){
  	  		  System.out.println( "player 1 got one point"); //top goal is player 2's goal

  	  		  puckPosition.y=1.1f;
  			  puckPosition.z=9.0f;
  	  		  V.x=0;
  	  		  V.y=0;
  	  		  V.z=0;}
//  	if the puck goes into the top goal
  	  	  else{
  	  		  puckTrans.set(new Vector3d(puckPosition.x,1.1,14.1));
  	  		  puckGrp.setTransform(puckTrans);
  	  		  V.z=-Math.abs(V.z);
  	  		 // System.out.println( "puck hit the up wall");
  	  	  
  	  	  }
  	    }
  	    else if(puckPosition.z<-14.1)  //if the puck hit the bottom wall
  	    {
  	  	  if(Math.abs(puckPosition.x)<1.6){
  	  		  System.out.println( "player 2 got one point"); //bottom goal is player 1's goal
  	  		  puckPosition.y=1.1f;
  	  		  puckPosition.z=-9.0f;
//  	  		  V.x=0;
//  			  V.y=0;
//  			  V.z=0;
  	  		  } //if the puck goes into the bottom goal
  	  	  else{
  	  		  puckPosition.z=-14.1f;
  	  		  puckPosition.y=1.1f;
  	  		  V.z=Math.abs(V.z);
  	  		//  System.out.println( "puck hit the bottom wall");
  	  		  }
  	  	  }
  	  
  	  if(puckPosition.x>4.1)  //if the handle hit the left wall
  	  {
  	  		puckPosition.x=4.1f;
  	  		V.x=-Math.abs(V.x);
  		//  System.out.println( "puck hit the left wall");
  		  }
  	  else if(puckPosition.x<-4.1)  //if the puck hit the right wall
  	  { 
  	  		puckPosition.x=-4.1f;
  	  		V.x=Math.abs(V.x);

  		  }
  	  
  	  if(puckPosition.y<1.1)  //if the puck go under the table
  	  {
  	  		puckPosition.y=1.1f;

  		  }
  	  if(Math.pow(handlePosition.x-puckPosition.x,2)+Math.pow(handlePosition.z-puckPosition.z,2)<0.64&&handlePosition.y>1.1&&handlePosition.y<1.3)
  	  {
  	  		//V= computeV(V ,puckPosition, handlePosition);
  	  	computeV(V ,puckPosition, handlePosition);
  	  
  	  }
  	  //System.out.println(V);
  	  puckPosition.add(V);
  	  puckTrans.set(puckPosition);
  	  puckGrp.setTransform(puckTrans);
  	  
  	}
  	
    this.wakeupOn(new WakeupOnElapsedFrames(1));
  }
  

	private void computeV(Vector3f OrgV,Vector3f pPos, Vector3f hPos) {
		
		Vector3f newV= new Vector3f();
		newV.y=0;
		newV.x=OrgV.x;
		newV.z=OrgV.z;
		double base= Math.abs(pPos.x-hPos.x)+Math.abs(pPos.z-hPos.z);
		double result1;
		double result2;
		
		
		result1=(Math.sqrt(Math.pow(newV.x,2)+Math.pow(newV.z,2))+0.2)*(pPos.x-hPos.x)/base;
		OrgV.x=(float) result1;
		result2= (Math.sqrt(Math.pow(newV.x,2)+Math.pow(newV.z,2))+0.2)*(pPos.z-hPos.z)/base;
		OrgV.z= (float)result2;
		//return newV;
	}
	
	
	
  
 }

